package com.hhkj.admin.bank.common.component.checker;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.hhkj.admin.bank.common.cont.QuestionOrderRuleConst;
import com.hhkj.admin.bank.common.cont.RuleConst;
import com.hhkj.admin.bank.domain.BankRule;
import com.hhkj.admin.bank.model.extend.QuestionOrderRule;
import com.hhkj.admin.bank.model.extend.RuleConfValidError;
import com.hhkj.admin.bank.model.req.BankRuleReq;
import com.hhkj.admin.course.domain.Course;
import com.hhkj.admin.course.service.base.CourseService;
import com.hhkj.admin.course.service.extend.CourseBankTypeExtendService;
import com.hhkj.admin.course.service.extend.CourseExtendService;
import com.hhkj.admin.question.common.cont.QuestionTypeEnum;
import com.ruoyi.common.exception.GlobalErrorListException;
import com.ruoyi.common.exception.GlobalException;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * RuleChecker
 *
 * @author HHKJ-SERVER-ZJ
 * @since 2023/6/8 15:38
 */
@Component
public class RuleChecker
{
    @Autowired
    private CourseService courseService;
    @Autowired
    private CourseExtendService courseExtendService;

    @Autowired
    private CourseBankTypeExtendService courseBankTypeExtendService;

    /**
     * 检验科目配置信息
     *
     * @param req 抽提规则信息
     */
    public void checkChildren(BankRuleReq req)
    {
        List<RuleConfValidError> confValidErrorList = new ArrayList<>();
        if (!req.hasCourseChildrenRule()) {
            List<String> allErrorList = new ArrayList<>();
            List<String> practiseErrorList = this.checkPractiseRuleError(req);
            if (CollectionUtil.isNotEmpty(practiseErrorList)) {
                allErrorList.addAll(practiseErrorList);
            }
            List<String> testRuleErrorList = this.checkTestRuleError(req);
            if (CollectionUtil.isNotEmpty(testRuleErrorList)) {
                allErrorList.addAll(practiseErrorList);
            }
            if (CollectionUtil.isNotEmpty(allErrorList)) {
                Course courseParent = courseService.getById(req.getCourseParentId());
                confValidErrorList.add(new RuleConfValidError(courseParent.getName(), allErrorList));
            }
        } else {
            List<Course> childrenCoursePoList = courseExtendService.listByParentId(req.getCourseParentId());
            List<Long> ruleCourseIdList = req.getChildren().stream().map(BankRule::getCourseId)
                    .collect(Collectors.toList());
            List<Long> coursePoIdList
                    = childrenCoursePoList.stream().map(Course::getId).collect(Collectors.toList());
            if (!CollectionUtils.isEqualCollection(ruleCourseIdList, coursePoIdList)) {
                throw new GlobalException("指定科目信息不正确");
            }
            boolean isPractiseDifferent
                    = RuleConst.ConfModeType.DIFFERENCE.getCode().equals(req.getPracticeConfModeTypeCode());
            boolean isTestDifferent
                    = RuleConst.ConfModeType.DIFFERENCE.getCode().equals(req.getTestConfModeTypeCode());

            List<String> practiseErrorList;
            List<String> testRuleErrorList;
            List<String> allErrorList;
            Map<Long, String> courseNameMapById = childrenCoursePoList.stream()
                    .collect(Collectors.toMap(Course::getId, Course::getName));
            for (BankRule childRule : req.getChildren()) {
                allErrorList = new ArrayList<>();
                if (isPractiseDifferent) {
                    practiseErrorList = this.checkPractiseRuleError(childRule);
                    if (CollectionUtil.isNotEmpty(practiseErrorList)) {
                        allErrorList.addAll(practiseErrorList);
                    }
                }
                if (isTestDifferent) {
                    testRuleErrorList = this.checkTestRuleError(childRule);
                    if (CollectionUtil.isNotEmpty(testRuleErrorList)) {
                        allErrorList.addAll(testRuleErrorList);
                    }
                }
                if (CollectionUtil.isNotEmpty(allErrorList)) {
                    confValidErrorList.add(new RuleConfValidError(courseNameMapById.get(childRule.getCourseId()), allErrorList));
                }
            }
        }
        if (CollectionUtil.isNotEmpty(confValidErrorList)) {
            throw new GlobalErrorListException(confValidErrorList, "规则格式错误");
        }
    }

    /**
     * 题目规则格式校验
     *
     * @param modelName 模式名称
     * @param orderRule 规则信息
     * @param errorList 错误信息
     */
    private void checkQuestionOrderRule(String modelName, QuestionOrderRule orderRule, List<String> errorList)
    {
        if (StrUtil.isBlank(orderRule.getTypeCode())) {
            errorList.add(modelName + "排序类型编码规则不能为空 顺序打乱 disruption 手动排序 manualSortType");
        } else {
            if (!QuestionOrderRuleConst.Type.getCodeSet()
                    .contains(orderRule.getTypeCode())) {
                errorList.add(modelName + "排序类型编码规则错误 顺序打乱 disruption 手动排序 manualSortType");
            } else if (QuestionOrderRuleConst.Type.MANUAL_SORT_TYPE.getCode()
                    .equals(orderRule.getTypeCode())) {
                if (CollectionUtil.isEmpty(orderRule.getQuestionTypeCodeList())) {
                    errorList.add(modelName + "排序题目类型编码列表不能为空 single 单选题、 multiple 多选题、 judge 判断题、 case 案例题");
                } else {
                    Set<String> codeSet = QuestionTypeEnum.getCodeSet();
                    for (String typeCode : orderRule.getQuestionTypeCodeList()) {
                        if (!codeSet.contains(typeCode)) {
                            errorList.add(modelName + "排序题目类型编码错误 single 单选题、 multiple 多选题、 judge 判断题、 case 案例题");
                            break;
                        }
                    }
                }
            }
        }
    }

    /** 题目排序规则校验 */
    private List<String> checkPractiseRuleError(BankRule bankRule)
    {
        List<String> errorList = new ArrayList<>();
        // 1、练习题库占比
        if (ObjectUtil.isNull(bankRule.getPracticePercent())) {
            errorList.add("练习占总题库百分比不能为空");
        } else if (BigDecimal.ZERO.compareTo(bankRule.getPracticePercent()) > 0
                || new BigDecimal(100).compareTo(bankRule.getPracticePercent()) < 0) {
            errorList.add("练习占总题库百分比范围为0~100");
        }
        // 2、练习题库排序规则
        // 4、测试题目排序规则
        if (ObjectUtil.isNull(bankRule.getPracticeOrderRule())) {
            errorList.add("练习题目排序规则不能为空");
        } else {
            QuestionOrderRule orderRule = bankRule.getPracticeOrderRule();
            this.checkQuestionOrderRule("练习模式", orderRule, errorList);
        }
        // 3、练习模式
        if (CollectionUtil.isEmpty(bankRule.getPracticeModeCodeList())) {
            errorList.add("练习模式不能为空");
        } else {
            for (String practiceModeCode : bankRule.getPracticeModeCodeList()) {
                Set<String> codeSet = RuleConst.PracticeMode.getCodeSet();
                if (!codeSet.contains(practiceModeCode)) {
                    errorList.add("测试题库规则指定类别错误: 答题模式:answer、背题模式:recitation");
                }
            }
        }
        return errorList;
    }

    /** 检查测试规则配置格式错误信息 */
    private List<String> checkTestRuleError(BankRule bankRule)
    {
        List<String> errorList = new ArrayList<>();
        // 1、测试题库中占练习题库百分比
        if (ObjectUtil.isNull(bankRule.getTestResiduePercent())) {
            errorList.add("测试题库中占练习题库百分比不能为空");
        } else if (BigDecimal.ZERO.compareTo(bankRule.getTestPracticePercent()) > 0
                || new BigDecimal(100).compareTo(bankRule.getTestPracticePercent()) < 0) {
            errorList.add("测试题库中占练习题库百分比范围为0~100");
        }
        // 2、测试题库中占剩余题库百分比
        if (ObjectUtil.isNull(bankRule.getTestResiduePercent())) {
            errorList.add("测试题库中占剩余题库百分比不能为空");
        } else if (BigDecimal.ZERO.compareTo(bankRule.getTestPracticePercent()) > 0
                || new BigDecimal(100).compareTo(bankRule.getTestPracticePercent()) < 0) {
            errorList.add("测试题库中占练习题库百分比范围为0~100");
        }
        // 3、测试时长
        if (ObjectUtil.isNull(bankRule.getTestDurationMinute())) {
            errorList.add("测试时长分钟不能为空");
        } else if (bankRule.getTestDurationMinute() <= 0) {
            errorList.add("测试时长分钟需要大于0");
        }
        if (ObjectUtil.isNull(bankRule.getTestAmountConfMap())) {
            errorList.add("测试题目数量配置不能为空");
        }
        if (ObjectUtil.isNull(bankRule.getTestCorrectConfMap())) {
            errorList.add("测试题目分数配置不能为空");
        }
        // 4、测试题目排序规则
        if (ObjectUtil.isNull(bankRule.getTestOrderRule())) {
            errorList.add("测试题目排序规则不能为空");
        } else {
            this.checkQuestionOrderRule("练习模式", bankRule.getTestOrderRule(), errorList);
        }
        return errorList;
    }

    /**
     * 校验课程题库类型信息
     *
     * @param courseParentId   课程id
     * @param courseBankTypeId 课程题库id
     */
    public void checkCourseBankType(Long courseParentId, Long courseBankTypeId)
    {
        courseBankTypeExtendService.getByCourseIdAndIdNotDisable(courseParentId, courseBankTypeId);
    }

    /**
     * 校验课程信息
     *
     * @param courseParentId 题库规则信息
     */
    public void checkCourseParent(Long courseParentId)
    {
        courseExtendService.getLevelNumSecondByIdNotDisable(courseParentId);
    }
}
